/* * Copyright (c) 2012, 2013, Werner Keil, Credit Suisse (Anatole Tresch). * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * * Contributors: Anatole Tresch - initial version. */ package org.javamoney.cdi.internal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.annotation.Annotation; import java.util.*; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.Instance; import javax.enterprise.inject.Vetoed; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.CDI; import javax.enterprise.util.TypeLiteral; import javax.inject.Named; import javax.naming.InitialContext; /** * Small utility class that glues together service loading and CDI, including support for different CDI version. */ final class CDIAccessor { private static final Logger LOG = LoggerFactory.getLogger(CDIAccessor.class); private static final Instance<?> EMPTY_INSTANCE = new EmptyInstance<>(); private CDIAccessor() { } private static <T> Instance<T> emptyInstance() { return Instance.class.cast(EMPTY_INSTANCE); } public static <T> Optional<T> getInstance(Class<T> instanceType, Annotation... qualifiers) { BeanManager man = getBeanManager(); if (man != null) { return Optional.ofNullable(getInstanceByType(man, instanceType, qualifiers)); } return Optional.empty(); } private static BeanManager getBeanManager() { // 1 try JNDI try { InitialContext ctx = new InitialContext(); BeanManager man = (BeanManager) ctx.lookup("comp:/env/BeanManager"); if (man != null) { return man; } } catch (Exception e) { LoggerFactory.getLogger(CDIAccessor.class).debug("Unable to locate BeanManager from JNDI...", e); } try { Class.forName("javax.enterprise.inject.spi.CDI"); // OK CDI 1.1 is loaded return CDI.current().getBeanManager(); } catch (ClassNotFoundException e) { LoggerFactory.getLogger(CDIAccessor.class).debug("CDI accessor not available (CDI 1.0)."); } catch (Exception e) { LoggerFactory.getLogger(CDIAccessor.class).debug("Unable to locate BeanManager from CDI providers...", e); } // 3 error, CDI not loaded... throw new IllegalStateException("CDI is not available."); } /** * Utility method allowing managed instances of beans to provide entry points * for non-managed beans (such as {@link org.jboss.weld.environment.se.WeldContainer}). Should only called * once Weld has finished booting. * * @param manager the BeanManager to use to access the managed instance * @param type the type of the Bean * @param bindings the bean's qualifiers * @return a managed instance of the bean * @throws IllegalArgumentException if the given type represents a type * variable * @throws IllegalArgumentException if two instances of the same qualifier * type are given * @throws IllegalArgumentException if an instance of an annotation that is * not a qualifier type is given * @throws javax.enterprise.inject.UnsatisfiedResolutionException if no beans can be resolved * @throws * AmbiguousResolutionException if the ambiguous dependency * resolution rules fail * @throws IllegalArgumentException if the given type is not a bean type of * the given bean */ private static <T> T getInstanceByType(BeanManager manager, Class<T> type, Annotation... bindings) { final Bean<?> bean = manager.resolve(manager.getBeans(type)); if (bean == null) { return null; } CreationalContext<?> cc = manager.createCreationalContext(bean); return type.cast(manager.getReference(bean, type, cc)); } public static <T> Instance<T> getInstances(Class<T> instanceType, Annotation... qualifiers) { try { return getInstance(Instance.class).get().select(instanceType, qualifiers); } catch (Exception e) { LOG.info("Failed to load instances from CDI.", e); return emptyInstance(); } } public static Set<?> getInstances(String name) { try { return getBeanManager().getBeans(name); } catch (Exception e) { LOG.info("Failed to load instances from CDI.", e); return Collections.emptySet(); } } public static void fireEvent(Object evt, Annotation... qualifiers) { try { getBeanManager().fireEvent(evt, qualifiers); } catch (Exception e) { LOG.info("Failed to fire event from CDI.", e); } } @SuppressWarnings("unchecked") public static <T> T getNamedInstance(Class<T> type, String id) { try { Set<?> found = getBeanManager().getBeans(id); if (found.isEmpty()) { return null; } for (Object object : found) { if (type.isAssignableFrom(object.getClass())) { return (T) object; } } return null; } catch (Exception e) { LOG.info("Failed to load instances from CDI.", e); return null; } } public static String getName(Object o) { if (o == null) { return "<null>"; } Named named = o.getClass().getAnnotation(Named.class); if (named != null) { return named.value(); } return o.getClass().getSimpleName(); } @Vetoed private static final class EmptyInstance<T> implements Instance<T> { @Override public Instance<T> select(Annotation... annotations) { return this; } @Override public <U extends T> Instance<U> select(Class<U> uClass, Annotation... annotations) { return new EmptyInstance<>(); } @Override public <U extends T> Instance<U> select(TypeLiteral<U> uTypeLiteral, Annotation... annotations) { return new EmptyInstance<>(); } @Override public boolean isUnsatisfied() { return true; } @Override public boolean isAmbiguous() { return false; } @Override public void destroy(T t) { } @Override public Iterator<T> iterator() { return Collections.emptyIterator(); } @Override public T get() { throw new NoSuchElementException(); } } }